﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using GameFramework.DataTable;
using UnityGameFramework.Runtime;

namespace LS
{
    public static class DataTableExtension
    {
        private const string DataRowClassPrefixName = "LS.DR";
        public static readonly char[] DataSplitSeparators = new char[] { '\t' };
        public static readonly char[] DataStructSplitSeparators = new char[] { ',' };
        public static readonly char[] DataArraySplitSeparators = new char[] { ';' };
        public static readonly char[] DataKeyValueSplitSeparators = new char[] { ':' };
        public static readonly char[] DataTrimSeparators = new char[] { '\"' };

        public static readonly HashSet<string> DefaultDataNames = new HashSet<string>()
        {
            "Scene",
            "Entity",
            "Music",
            "Sound",
            "UIForm",
            "UISound",
        };

        public static readonly Dictionary<string, string> DefaultDataTypeMap = new Dictionary<string, string>()
        {
            ["Scene"]="LS.DataTable.DTScene",
            ["Entity"] = "LS.DataTable.DTEntity",
            ["Music"] = "LS.DataTable.DTMusic",
            ["Sound"] = "LS.DataTable.DTSound",
            ["UIForm"] = "LS.DataTable.DTUIForm",
            ["UISound"] = "LS.DataTable.DTUISound",
        };

        public static void LoadDataTable(this DataTableComponent dataTableComponent, string dataTableName, string dataTableAssetName, object userData)
        {
            if (string.IsNullOrEmpty(dataTableName))
            {
                Log.Warning("Data table name is invalid.");
                return;
            }

            string[] splitedNames = dataTableName.Split('_');
            if (splitedNames.Length > 2)
            {
                Log.Warning("Data table name is invalid.");
                return;
            }
            string dataRowClassName = null;
            Type dataRowType = null;
            if (DefaultDataNames.Contains(splitedNames[0]))
            {
                dataRowClassName = LSEntry.LSBase.m_DataTableDefaultSetting.GetTypeStringByName(splitedNames[0]);
                dataRowType = LSEntry.LSBase.m_DataTableDefaultSetting.GetTypeByName(splitedNames[0]);
            }
            else
            {
                dataRowClassName = DataRowClassPrefixName + splitedNames[0];
                dataRowType = GameFramework.Utility.Assembly.GetType(dataRowClassName);
            }
            
            if (dataRowType == null)
            {
                Log.Warning("Can not get data row type with class name '{0}'.", dataRowClassName);
                return;
            }

            string name = splitedNames.Length > 1 ? splitedNames[1] : null;
            DataTableBase dataTable = dataTableComponent.CreateDataTable(dataRowType, name);
            dataTable.ReadData(dataTableAssetName, Constant.AssetPriority.DataTableAsset, userData);
        }

        public static T GetDataRow<T>(this DataTableComponent dataTableComponent,int id)
             where T : IDataRow
        {
            var dt = dataTableComponent.GetDataTable<T>();
            if (dt.HasDataRow(id))
            {
                return dt.GetDataRow(id);
            }
            return default;
        }
        
        public static IDataRow GetDataRow(this DataTableComponent dataTableComponent, Type dataTableType, int id)
        {
            DataTableBase dataTable = dataTableComponent.GetDataTable(dataTableType);
            IDataRow row = null;
            foreach (IDataRow item in (IEnumerable)dataTable)
            {
                if (item.Id == id)
                {
                    row = item;
                    break;
                }
            }
            return row;
        }
        
        public static IDataRow GetDataRow(this DataTableBase dataTable, int id)
        {
            IDataRow row = null;
            foreach (IDataRow item in (IEnumerable)dataTable)
            {
                if (item.Id == id)
                {
                    row = item;
                    break;
                }
            }

            return row;
        }
        
        public static Color32 ParseColor32(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Color.white;
            }
            string[] splitedValue = value.Split(',');
            return new Color32(byte.Parse(splitedValue[0]), byte.Parse(splitedValue[1]), byte.Parse(splitedValue[2]), byte.Parse(splitedValue[3]));
        }

        public static Color ParseColor(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Color.white;
            }
            string[] splitedValue = value.Split(',');
            return new Color(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Quaternion ParseQuaternion(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Quaternion.identity;
            }
            string[] splitedValue = value.Split(',');
            return new Quaternion(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Rect ParseRect(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Rect.zero;
            }
            string[] splitedValue = value.Split(',');
            return new Rect(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Vector2 ParseVector2(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Vector2.zero;
            }
            string[] splitedValue = value.Split(',');
            return new Vector2(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]));
        }

        public static Vector3 ParseVector3(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return default;
            }
            string[] splitedValue = value.Split(',');
            return new Vector3(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]));
        }

        public static Vector4 ParseVector4(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return default;
            }
            string[] splitedValue = value.Split(',');
            return new Vector4(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static bool[] ParseBooleanArray(string value)
        {
            return ParseArray<bool>(value, (str) => bool.Parse(str));
        }

        public static List<bool> ParseBooleanList(string value)
        {
            return ParseList<bool>(value, (str) => bool.Parse(str));
        }

        public static Dictionary<string, bool> ParseBooleanDictionary(string value)
        {
            return ParseDictionary<bool>(value, (str) => bool.Parse(str));
        }

        public static byte[] ParseByteArray(string value)
        {
            return ParseArray<byte>(value, (str) => byte.Parse(str));
        }

        public static List<byte> ParseByteList(string value)
        {
            return ParseList<byte>(value, (str) => byte.Parse(str));
        }

        public static Dictionary<string, byte> ParseByteDictionary(string value)
        {
            return ParseDictionary<byte>(value, (str) => byte.Parse(str));
        }

        public static Color32[] ParseColor32Array(string value)
        {
            return ParseArray<Color32>(value, (str) => ParseColor32(str));
        }

        public static List<Color32> ParseColor32List(string value)
        {
            return ParseList<Color32>(value, (str) => ParseColor32(str));
        }

        public static Dictionary<string, Color32> ParseColor32Dictionary(string value)
        {
            return ParseDictionary<Color32>(value, (str) => ParseColor32(str));
        }

        public static Color[] ParseColorArray(string value)
        {
            return ParseArray<Color>(value, (str) => ParseColor(str));
        }

        public static List<Color> ParseColorList(string value)
        {
            return ParseList<Color>(value, (str) => ParseColor(str));
        }

        public static Dictionary<string, Color> ParseColorDictionary(string value)
        {
            return ParseDictionary<Color>(value, (str) => ParseColor32(str));
        }

        public static decimal[] ParseDecimalArray(string value)
        {
            return ParseArray<decimal>(value, (str) => decimal.Parse(str));
        }

        public static List<decimal> ParseDecimalList(string value)
        {
            return ParseList<decimal>(value, (str) => decimal.Parse(str));
        }

        public static Dictionary<string, decimal> ParseDecimalDictionary(string value)
        {
            return ParseDictionary<decimal>(value, (str) => decimal.Parse(str));
        }

        public static double[] ParseDoubleArray(string value)
        {
            return ParseArray<double>(value, (str) => double.Parse(str));
        }

        public static List<double> ParseDoubleList(string value)
        {
            return ParseList<double>(value, (str) => double.Parse(str));
        }

        public static Dictionary<string, double> ParseDoubleDictionary(string value)
        {
            return ParseDictionary<double>(value, (str) => double.Parse(str));
        }

        public static short[] ParseInt16Array(string value)
        {
            return ParseArray<short>(value, (str) => short.Parse(str));
        }

        public static List<short> ParseInt16List(string value)
        {
            return ParseList<short>(value, (str) => short.Parse(str));
        }

        public static Dictionary<string, short> ParseInt16Dictionary(string value)
        {
            return ParseDictionary<short>(value, (str) => short.Parse(str));
        }

        public static int[] ParseInt32Array(string value)
        {
            return ParseArray<int>(value, (str) => int.Parse(str));
        }

        public static List<int> ParseInt32List(string value)
        {
            return ParseList<int>(value, (str) => int.Parse(str));
        }

        public static Dictionary<string, int> ParseInt32Dictionary(string value)
        {
            return ParseDictionary<int>(value, (str) => int.Parse(str));
        }

        public static long[] ParseInt64Array(string value)
        {
            return ParseArray<long>(value, (str) => long.Parse(str));
        }

        public static List<long> ParseInt64List(string value)
        {
            return ParseList<long>(value, (str) => long.Parse(str));
        }

        public static Dictionary<string, long> ParseInt64Dictionary(string value)
        {
            return ParseDictionary<long>(value, (str) => long.Parse(str));
        }

        public static Quaternion[] ParseQuaternionArray(string value)
        {
            return ParseArray<Quaternion>(value, (str) => ParseQuaternion(str));
        }

        public static List<Quaternion> ParseQuaternionList(string value)
        {
            return ParseList<Quaternion>(value, (str) => ParseQuaternion(str));
        }

        public static Dictionary<string, Quaternion> ParseQuaternionDictionary(string value)
        {
            return ParseDictionary<Quaternion>(value, (str) => ParseQuaternion(str));
        }

        public static Rect[] ParseRectArray(string value)
        {
            return ParseArray<Rect>(value, (str) => ParseRect(str));
        }

        public static List<Rect> ParseRectList(string value)
        {
            return ParseList<Rect>(value, (str) => ParseRect(str));
        }

        public static Dictionary<string, Rect> ParseRectDictionary(string value)
        {
            return ParseDictionary<Rect>(value, (str) => ParseRect(str));
        }

        public static sbyte[] ParseSByteArray(string value)
        {
            return ParseArray<sbyte>(value, (str) => sbyte.Parse(str));
        }

        public static List<sbyte> ParseSByteList(string value)
        {
            return ParseList<sbyte>(value, (str) => sbyte.Parse(str));
        }

        public static Dictionary<string, sbyte> ParseSByteDictionary(string value)
        {
            return ParseDictionary<sbyte>(value, (str) => sbyte.Parse(str));
        }

        public static float[] ParseSingleArray(string value)
        {
            return ParseArray<float>(value, (str) => float.Parse(str));
        }

        public static List<float> ParseSingleList(string value)
        {
            return ParseList<float>(value, (str) => float.Parse(str));
        }

        public static Dictionary<string, float> ParseSingleDictionary(string value)
        {
            return ParseDictionary<float>(value, (str) => float.Parse(str));
        }

        public static string[] ParseStringArray(string value)
        {
            return ParseArray<string>(value, (str) => str);
        }

        public static List<string> ParseStringList(string value)
        {
            return ParseList<string>(value, (str) => str);
        }

        public static Dictionary<string, string> ParseStringDictionary(string value)
        {
            return ParseDictionary<string>(value, (str) => str);
        }

        public static ushort[] ParseUInt16Array(string value)
        {
            return ParseArray<ushort>(value, (str) => ushort.Parse(str));
        }

        public static List<ushort> ParseUInt16List(string value)
        {
            return ParseList<ushort>(value, (str) => ushort.Parse(str));
        }

        public static Dictionary<string, ushort> ParseUInt16Dictionary(string value)
        {
            return ParseDictionary<ushort>(value, (str) => ushort.Parse(str));
        }

        public static uint[] ParseUInt32Array(string value)
        {
            return ParseArray<uint>(value, (str) => uint.Parse(str));
        }

        public static List<uint> ParseUInt32List(string value)
        {
            return ParseList<uint>(value, (str) => uint.Parse(str));
        }

        public static Dictionary<string, uint> ParseUInt32Dictionary(string value)
        {
            return ParseDictionary<uint>(value, (str) => uint.Parse(str));
        }

        public static ulong[] ParseUInt64Array(string value)
        {
            return ParseArray<ulong>(value, (str) => ulong.Parse(str));
        }

        public static List<ulong> ParseUInt64List(string value)
        {
            return ParseList<ulong>(value, (str) => ulong.Parse(str));
        }

        public static Dictionary<string, ulong> ParseUInt64Dictionary(string value)
        {
            return ParseDictionary<ulong>(value, (str) => ulong.Parse(str));
        }

        public static Vector2[] ParseVector2Array(string value)
        {
            return ParseArray<Vector2>(value, (str) => ParseVector2(str));
        }

        public static List<Vector2> ParseVector2List(string value)
        {
            return ParseList<Vector2>(value, (str) => ParseVector2(str));
        }

        public static Dictionary<string, Vector2> ParseVector2Dictionary(string value)
        {
            return ParseDictionary<Vector2>(value, (str) => ParseVector2(str));
        }

        public static Vector3[] ParseVector3Array(string value)
        {
            return ParseArray<Vector3>(value, (str) => ParseVector3(str));
        }

        public static List<Vector3> ParseVector3List(string value)
        {
            return ParseList<Vector3>(value, (str) => ParseVector3(str));
        }

        public static Dictionary<string, Vector3> ParseVector3Dictionary(string value)
        {
            return ParseDictionary<Vector3>(value, (str) => ParseVector3(str));
        }

        public static Vector4[] ParseVector4Array(string value)
        {
            return ParseArray<Vector4>(value, (str) => ParseVector4(str));
        }

        public static List<Vector4> ParseVector4List(string value)
        {
            return ParseList<Vector4>(value, (str) => ParseVector4(str));
        }

        public static Dictionary<string, Vector4> ParseVector4Dictionary(string value)
        {
            return ParseDictionary<Vector4>(value, (str) => ParseVector4(str));
        }

        public static System.Numerics.BigInteger[] ParseBigIntegerArray(string value)
        {
            return ParseArray<System.Numerics.BigInteger>(value, (str) => System.Numerics.BigInteger.Parse(str));
        }

        public static List<System.Numerics.BigInteger> ParseBigIntegerList(string value)
        {
            return ParseList<System.Numerics.BigInteger>(value, (str) => System.Numerics.BigInteger.Parse(str));
        }

        public static Dictionary<string, System.Numerics.BigInteger> ParseBigIntegerDictionary(string value)
        {
            return ParseDictionary<System.Numerics.BigInteger>(value, (str) => System.Numerics.BigInteger.Parse(str));
        }
#if BIG_DECIMAL
        public static ExtendedNumerics.BigDecimal[] ParseBigDecimalArray(string value)
        {
            return ParseArray<ExtendedNumerics.BigDecimal>(value, (str) => ExtendedNumerics.BigDecimal.Parse(str));
        }

        public static List<ExtendedNumerics.BigDecimal> ParseBigDecimalList(string value)
        {
            return ParseList<ExtendedNumerics.BigDecimal>(value, (str) => ExtendedNumerics.BigDecimal.Parse(str));
        }

        public static Dictionary<string, ExtendedNumerics.BigDecimal> ParseBigDecimalDictionary(string value)
        {
            return ParseDictionary<ExtendedNumerics.BigDecimal>(value, (str) => ExtendedNumerics.BigDecimal.Parse(str));
        }
#endif
        public static T[] ParseArray<T>(string value,Func<string,T> parseItem)
        {
            if (string.IsNullOrEmpty(value))
            {
                return new T[0];
            }
            string[] splitedValue = value.Split(';', StringSplitOptions.RemoveEmptyEntries);
            T[] array = new T[splitedValue.Length];
            for (int i = 0; i < splitedValue.Length; i++)
            {
                array[i] = parseItem(splitedValue[i]);
            }
            return array;
        }
        public static List<T> ParseList<T>(string value, Func<string, T> parseItem)
        {
            if (string.IsNullOrEmpty(value))
            {
                return new List<T>();
            }
            string[] splitedValue = value.Split(';', StringSplitOptions.RemoveEmptyEntries);
            List<T> list = new List<T>(splitedValue.Length);
            for (int i = 0; i < splitedValue.Length; i++)
            {
                list.Add(parseItem(splitedValue[i]));
            }
            return list;
        }
        public static Dictionary<string, T> ParseDictionary<T>(string value, Func<string, T> parseItem)
        {
            if (string.IsNullOrEmpty(value))
            {
                return new Dictionary<string, T>();
            }
            string[] splitedValue = value.Split(';', StringSplitOptions.RemoveEmptyEntries);
            Dictionary<string,T> dic = new Dictionary<string, T>(splitedValue.Length);
            for (int i = 0; i < splitedValue.Length; i++)
            {
                string[] splitItem = splitedValue[i].Split(':');
                dic.Add(splitItem[0],parseItem(splitItem[1]));
            }
            return dic;
        }
    }
}
